package com.heihei.dynamicarrays;

/**
 * 自建ArrayList
 *
 * @author duanhengfei
 * @version 1.0
 * @company 洛阳图联科技有限公司
 * @copyright (c) 2019 LuoYang TuLian Co'Ltd Inc. All rights reserved.
 * @date 2020/7/21 16:48
 * @since JDK1.8
 */
public class MyArrayList<T> {
    /**
     * 存储长度（元素数量）
     */
    private int size;

    /**
     * 所有的元素
     */
    private T[] elements;

    /**
     * 默认容量
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 元素未找到，返回 -1
     */
    private static final int ELEMENT_NOT_FOUND = -1;


    /**
     * 构造方法（可以指定初始容量）
     * @param  capacity 初始容量
     *
     * @author duanhengfei
     * @date 2020/7/21 16:59
     */
    public MyArrayList(int capacity) {
        capacity = capacity < DEFAULT_CAPACITY ? DEFAULT_CAPACITY : capacity;
        elements = (T[])new Object[capacity];
    }

    /**
     * 无参构造
     *
     * @author duanhengfei
     * @date 2020/7/21 16:59
     */
    public MyArrayList() {
        this(DEFAULT_CAPACITY);
    }

    /**
     * 获取当前list长度
     * @return  返回当前数组长度
     *
     * @author duanhengfei
     * @date 2020/7/21 17:00
     */
    public int size() {
        return this.size;
    }

    /**
     * 判断是否为空
     * @return 空 则返回ture，非空 则返回false
     *
     * @author duanhengfei
     * @date 2020/7/21 17:00
     */
    public boolean isEmpty() {
        return this.size == 0;
    }

    /***
     * 获取index位置的元素
     * @param index 索引
     * @return  该索引处的值
     *
     * @author duanhengfei
     * @date 2020/7/21 17:02
     */
    public T get(int index) {
        rangeCheck(index);
        return elements[index];
    }

    /**
     * 添加元素
     *
     * @param element 要添加的元素
     * @author duanhengfei
     * @date 2020/7/23 16:46
     */
    public void add(T element) {
        add(size, element);
        //稍等，再考虑扩容的问题
    }

    /**
     * 向指定索引位置添加元素
     *
     * @param
     * @return
     * @throws
     * @author duanhengfei
     * @date 2020/7/23 16:56
     */
    public void add(int index, T element) {
        //检查索引是否越界
        rangeCheckForAdd(index);
        //检测空间要足够（如果不够，则扩容）
        ensureCapacity(size + 1);
        for (int i = size - 1; i >= index; i--) {
            elements[i + 1] = elements[i];
        }
        elements[index] = element;
        size++;
    }

    /**
     *
     *
     * @author duanhengfei
     * @date 2020/8/20 10:12
     */
    private void ensureCapacity(int capacity) {
        int oldCapacity = elements.length;
        if(oldCapacity >= capacity) return;
        //新容量为旧容量的 1.5 倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        T[] newElement = (T[])new Object[newCapacity];
        for (int i = 0; i < size; i++) {
            newElement[i] = elements[i];
        }
        elements = newElement;
    }

    /**
     * 根据索引删除元素
     * @param index 要删除的元素的索引
     * @return 返回删除的元素
     * @author duanhengfei
     * @date 2020/7/23 16:46
     */
    public T remove(int index) {
        //判断index的合法性
        rangeCheck(index);
        T old = elements[index];
        for (int i = index; i < size - 1; i++) {
            elements[i] = elements[i+1];
        }
        size--;
        return old;
    }

    /**
     * 修改指定索引的值
     * @param index 索引
     * @param element  要修改的值
     * @return  返回原本该索引处的值
     *
     * @author duanhengfei
     * @date 2020/7/21 17:13
     */
    public T set(int index, T element) {
        rangeCheck(index);
        T preElement = elements[index];
        elements[index] = element;
        return preElement;
    }
    
    /**
     * 查看元素的索引
     * 
     * @param element 元素
     * @return 返回该元素在数组中的索引
     *
     * @author duanhengfei
     * @date 2020/7/21 17:17
     */
    public int indexOf(T element) {
        for (int i = 0; i < elements.length; i++) {
            if(elements[i].equals(element)) {
                return i;
            }
        }
        return ELEMENT_NOT_FOUND;
    }

    /**
     * 判断是否包含某元素
     *
     * @param element 元素
     * @return 当前数组包含该元素，则返回true；反之返回false
     *
     * @author duanhengfei
     * @date 2020/7/21 17:21
     */
    public boolean contains(T element) {
        return indexOf(element) != ELEMENT_NOT_FOUND;
    }
    
    /**
     * 清除所有元素
     * 
     * @author duanhengfei
     * @date 2020/7/21 17:29
     */
    public void clear() {
        this.size = 0;
    }


    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("size = ").append(size).append(", [");
        for (int i = 0; i < size; i++) {
            if(i != 0) {
                sb.append(", ");
            }
            sb.append(elements[i]);
//            if(i != size - 1) {
//                sb.append(", ")
//            }
        }
        sb.append("]");
        return sb.toString();
    }

    /**
     * 检查index范围（针对于删除、获取 等方法）
     *
     * @param index 索引
     * @throws
     * @author duanhengfei
     * @date 2020/7/23 17:48
     */
    public void rangeCheck(int index){
        if(index < 0 || index >= size) {
            outOfBound(index);
        }
    }

    /**
     * 检查index范围（针对于 添加方法）
     *
     * @param index 索引
     * @throws
     * @author duanhengfei
     * @date 2020/7/23 17:49
     */
    public void rangeCheckForAdd(int index) {
        if(index < 0 || index > size) {
            outOfBound(index);
        }
    }

    /**
     * 抛出数组越界异常
     *
     * @param index 索引
     * @throws
     * @author duanhengfei
     * @date 2020/7/23 17:50
     */
    public void outOfBound(int index) {
        throw new IndexOutOfBoundsException("index: " + index + ", but size: " + this.size);
    }
}